# -*- coding: utf-8 -*-
"""
数据服务模块 - 数据模型定义

本文件定义了测试DEMO中数据服务相关的所有数据模型，包括：

1. DataSource - 数据源配置模型
   - 管理系统中的各种数据源（AKShare、手动录入、第三方API等）
   - 存储数据源的连接配置和认证信息
   - 支持数据源的启用/禁用管理

2. DataSyncTask - 数据同步任务模型
   - 定义数据同步任务的配置和调度信息
   - 支持多种同步类型（基金列表、净值、业绩等）
   - 支持定时任务调度（基于Cron表达式）
   - 记录任务执行状态和时间

3. DataSyncLog - 数据同步日志模型
   - 记录每次数据同步任务的执行详情
   - 统计同步结果（总记录数、成功数、失败数）
   - 保存错误信息和详细日志
   - 支持同步过程的审计和问题排查

4. FundData - 基金数据模型
   - 存储基金的基本信息和静态数据
   - 包含基金代码、名称、类型、公司、经理等信息
   - 记录基金规模、费率、成立日期等关键指标
   - 与产品模型关联，支持产品化管理

5. FundNetValue - 基金净值模型
   - 存储基金的历史净值数据
   - 包含单位净值、累计净值和各期收益率
   - 支持日、周、月、季、年等多维度收益率计算
   - 按净值日期排序，便于时间序列分析

6. MarketData - 市场数据模型
   - 存储各种市场指标数据
   - 支持指标的变化值和变化率计算
   - 关联数据源，追踪数据来源
   - 支持多种市场指标的统一管理

这些模型构成了完整的金融数据管理体系，支持数据的采集、存储、
同步和查询，为上层业务提供可靠的数据基础。

Author: zhaozeliang
Date: 2025-01-14
"""

from django.db import models
from django.conf import settings
from decimal import Decimal
from products.models import Product

# 数据源类型
DATA_SOURCE_TYPES = [
    ('akshare', 'AKShare'),
    ('manual', '手动录入'),
    ('api', '第三方API'),
]

# 数据同步状态
SYNC_STATUS = [
    ('pending', '待同步'),
    ('running', '同步中'),
    ('success', '成功'),
    ('failed', '失败'),
    ('cancelled', '已取消'),
]

class DataSource(models.Model):
    """数据源配置"""
    name = models.CharField(max_length=100, verbose_name='数据源名称')
    source_type = models.CharField(max_length=20, choices=DATA_SOURCE_TYPES, verbose_name='数据源类型')
    api_url = models.URLField(blank=True, verbose_name='API地址')
    api_key = models.CharField(max_length=200, blank=True, verbose_name='API密钥')
    config = models.JSONField(default=dict, verbose_name='配置参数')
    
    is_active = models.BooleanField(default=True, verbose_name='是否启用')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '数据源'
        verbose_name_plural = '数据源'
        db_table = 'data_sources'
    
    def __str__(self):
        return self.name

class DataSyncTask(models.Model):
    """数据同步任务"""
    name = models.CharField(max_length=100, verbose_name='任务名称')
    data_source = models.ForeignKey(DataSource, on_delete=models.CASCADE, verbose_name='数据源')
    
    # 同步配置
    sync_type = models.CharField(max_length=50, verbose_name='同步类型')  # fund_list, fund_nav, fund_performance
    sync_params = models.JSONField(default=dict, verbose_name='同步参数')
    
    # 调度配置
    is_scheduled = models.BooleanField(default=False, verbose_name='是否定时执行')
    cron_expression = models.CharField(max_length=100, blank=True, verbose_name='Cron表达式')
    
    # 状态
    status = models.CharField(max_length=20, choices=SYNC_STATUS, default='pending', verbose_name='状态')
    last_sync_time = models.DateTimeField(null=True, blank=True, verbose_name='最后同步时间')
    next_sync_time = models.DateTimeField(null=True, blank=True, verbose_name='下次同步时间')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '数据同步任务'
        verbose_name_plural = '数据同步任务'
        db_table = 'data_sync_tasks'
    
    def __str__(self):
        return self.name

class DataSyncLog(models.Model):
    """数据同步日志"""
    task = models.ForeignKey(DataSyncTask, on_delete=models.CASCADE, verbose_name='同步任务')
    
    # 执行信息
    start_time = models.DateTimeField(verbose_name='开始时间')
    end_time = models.DateTimeField(null=True, blank=True, verbose_name='结束时间')
    status = models.CharField(max_length=20, choices=SYNC_STATUS, verbose_name='状态')
    
    # 结果统计
    total_records = models.IntegerField(default=0, verbose_name='总记录数')
    success_records = models.IntegerField(default=0, verbose_name='成功记录数')
    failed_records = models.IntegerField(default=0, verbose_name='失败记录数')
    
    # 错误信息
    error_message = models.TextField(blank=True, verbose_name='错误信息')
    error_details = models.JSONField(null=True, blank=True, verbose_name='错误详情')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '数据同步日志'
        verbose_name_plural = '数据同步日志'
        db_table = 'data_sync_logs'
        ordering = ['-created_at']
    
    def __str__(self):
        return f'{self.task.name} - {self.start_time}'

class FundInfo(models.Model):
    """基金信息表 - 存储基金的基本信息"""
    # 基金基本信息
    fund_code = models.CharField(max_length=20, unique=True, verbose_name='基金代码')
    fund_name = models.CharField(max_length=200, verbose_name='基金名称')
    fund_type = models.CharField(max_length=50, verbose_name='基金类型')
    fund_company = models.CharField(max_length=200, verbose_name='基金公司')
    fund_manager = models.CharField(max_length=100, verbose_name='基金经理')
    
    # 基金详细信息
    establishment_date = models.DateField(null=True, blank=True, verbose_name='成立日期')
    fund_size = models.DecimalField(max_digits=15, decimal_places=2, null=True, blank=True, verbose_name='基金规模')
    management_fee = models.DecimalField(max_digits=5, decimal_places=4, null=True, blank=True, verbose_name='管理费率')
    custodian_fee = models.DecimalField(max_digits=5, decimal_places=4, null=True, blank=True, verbose_name='托管费率')
    
    # 投资相关信息
    benchmark = models.CharField(max_length=500, blank=True, verbose_name='业绩比较基准')
    investment_objective = models.TextField(blank=True, verbose_name='投资目标')
    investment_scope = models.TextField(blank=True, verbose_name='投资范围')
    risk_level = models.CharField(max_length=20, blank=True, verbose_name='风险等级')
    
    # 状态和数据来源
    status = models.CharField(max_length=20, default='active', verbose_name='状态')
    data_source = models.CharField(max_length=50, default='akshare', verbose_name='数据来源')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '基金信息'
        verbose_name_plural = '基金信息'
        db_table = 'fund_info'
        indexes = [
            models.Index(fields=['fund_code']),
            models.Index(fields=['fund_type']),
            models.Index(fields=['fund_company']),
            models.Index(fields=['status']),
        ]
    
    def __str__(self):
        return f'{self.fund_code} - {self.fund_name}'

class FundInfoDetail(models.Model):
    """基金详细信息表 - 存储基金的详细信息"""
    fund_code = models.CharField(max_length=20, unique=True, verbose_name='基金代码')
    fund_name = models.CharField(max_length=200, blank=True, default='', verbose_name='基金名称')
    fund_full_name = models.CharField(max_length=300, blank=True, default='', verbose_name='基金全称')
    establishment_date = models.DateField(null=True, blank=True, verbose_name='成立时间')
    latest_scale = models.CharField(max_length=100, blank=True, default='', verbose_name='最新规模')
    fund_company = models.CharField(max_length=200, blank=True, default='', verbose_name='基金公司')
    fund_manager = models.CharField(max_length=200, blank=True, default='', verbose_name='基金经理')
    custodian_bank = models.CharField(max_length=200, blank=True, default='', verbose_name='托管银行')
    fund_type = models.CharField(max_length=100, blank=True, default='', verbose_name='基金类型')
    rating_agency = models.CharField(max_length=100, blank=True, default='', verbose_name='评级机构')
    fund_rating = models.CharField(max_length=100, blank=True, default='', verbose_name='基金评级')
    investment_strategy = models.TextField(blank=True, default='', verbose_name='投资策略')
    investment_objective = models.TextField(blank=True, default='', verbose_name='投资目标')
    performance_benchmark = models.CharField(max_length=500, blank=True, default='', verbose_name='业绩比较基准')
    
    # 数据来源和时间戳
    data_source = models.CharField(max_length=50, default='akshare', verbose_name='数据来源')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '基金详细信息'
        verbose_name_plural = '基金详细信息'
        db_table = 'fund_info_detail'
        indexes = [
            models.Index(fields=['fund_code']),
            models.Index(fields=['fund_company']),
            models.Index(fields=['fund_type']),
        ]
        ordering = ['fund_code']
    
    def __str__(self):
        return f'{self.fund_code} - {self.fund_name}'



class MarketData(models.Model):
    """市场数据"""
    # 市场指标
    indicator_name = models.CharField(max_length=100, verbose_name='指标名称')
    indicator_code = models.CharField(max_length=50, verbose_name='指标代码')
    
    # 数据值
    data_date = models.DateField(verbose_name='数据日期')
    value = models.DecimalField(max_digits=15, decimal_places=4, verbose_name='数据值')
    
    # 变化情况
    change_value = models.DecimalField(max_digits=15, decimal_places=4, null=True, blank=True, verbose_name='变化值')
    change_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='变化率')
    
    # 数据来源
    data_source = models.ForeignKey(DataSource, on_delete=models.CASCADE, verbose_name='数据源')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '市场数据'
        verbose_name_plural = '市场数据'
        db_table = 'market_data'
        unique_together = ['indicator_code', 'data_date']
        ordering = ['-data_date']
    
    def __str__(self):
        return f'{self.indicator_name} - {self.data_date}'

class FundNavRanking(models.Model):
    """基金排行数据模型（基于AKShare fund_info_index_em接口）"""
    fund_code = models.CharField(max_length=10, verbose_name='基金代码')
    fund_name = models.CharField(max_length=200, blank=True, verbose_name='基金名称')
    
    # 净值信息
    unit_nav = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True, verbose_name='单位净值')
    nav_date = models.DateField(null=True, blank=True, verbose_name='净值日期')
    
    # 增长率信息
    daily_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='日增长率(%)')
    weekly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1周(%)')
    monthly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1月(%)')
    quarterly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3月(%)')
    half_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近6月(%)')
    yearly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1年(%)')
    two_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近2年(%)')
    three_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3年(%)')
    ytd_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='今年来(%)')
    since_inception_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='成立来(%)')
    
    # 费用和购买信息
    fee_rate = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True, verbose_name='手续费(%)')
    min_purchase_amount = models.CharField(max_length=50, blank=True, verbose_name='起购金额')
    tracking_target = models.CharField(max_length=200, blank=True, verbose_name='跟踪标的')
    tracking_method = models.CharField(max_length=100, blank=True, verbose_name='跟踪方式')
    
    # 分类信息
    symbol_category = models.CharField(max_length=50, blank=True, verbose_name='symbol分类')
    indicator_type = models.CharField(max_length=50, blank=True, verbose_name='indicator类型')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '基金排行数据'
        verbose_name_plural = '基金排行数据'
        db_table = 'fund_nav_ranking'
        unique_together = [['fund_code', 'nav_date', 'symbol_category', 'indicator_type']]
        indexes = [
            models.Index(fields=['fund_code'], name='idx_fund_code'),
            models.Index(fields=['nav_date'], name='idx_nav_date'),
            models.Index(fields=['fund_code', 'nav_date'], name='idx_fund_date'),
            models.Index(fields=['daily_growth_rate'], name='idx_daily_growth'),
            models.Index(fields=['yearly_growth_rate'], name='idx_yearly_growth'),
            models.Index(fields=['symbol_category', 'indicator_type'], name='idx_symbol_indicator'),
        ]
        ordering = ['-nav_date', 'fund_code']
    
    def __str__(self):
        return f"{self.fund_code} - {self.fund_name} ({self.nav_date})"

class FundNavScrapyRanking(models.Model):
    """基金排行爬虫数据表 - 存储从东方财富基金排行页面爬取的数据"""
    # 基金基本信息
    fund_code = models.CharField(max_length=10, verbose_name='基金代码')
    fund_name = models.CharField(max_length=200, blank=True, verbose_name='基金名称')
    
    # 净值信息
    unit_nav = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True, verbose_name='单位净值')
    accumulated_nav = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True, verbose_name='累计净值')
    nav_date = models.DateField(null=True, blank=True, verbose_name='净值日期')
    
    # 收益率信息
    daily_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='日增长率(%)')
    weekly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1周(%)')
    monthly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1月(%)')
    quarterly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3月(%)')
    half_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近6月(%)')
    yearly_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1年(%)')
    two_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近2年(%)')
    three_year_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3年(%)')
    ytd_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='今年来(%)')
    since_inception_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='成立来(%)')
    
    # 费用和购买信息
    fee_rate = models.DecimalField(max_digits=6, decimal_places=4, null=True, blank=True, verbose_name='手续费(%)')
    min_purchase_amount = models.CharField(max_length=50, blank=True, verbose_name='起购金额')
    
    # 排行信息
    ranking_position = models.IntegerField(null=True, blank=True, verbose_name='排行位置')
    fund_type = models.CharField(max_length=50, blank=True, verbose_name='基金类型')
    
    # 爬取相关信息
    scrape_date = models.DateTimeField(auto_now_add=True, verbose_name='爬取时间')
    data_source_url = models.URLField(blank=True, verbose_name='数据源URL')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '基金排行爬虫数据'
        verbose_name_plural = '基金排行爬虫数据'
        db_table = 'fund_nav_scrapy_ranking'
        unique_together = [['fund_code', 'nav_date']]
        indexes = [
            models.Index(fields=['fund_code'], name='idx_scrapy_fund_code'),
            models.Index(fields=['nav_date'], name='idx_scrapy_nav_date'),
            models.Index(fields=['fund_code', 'nav_date'], name='idx_scrapy_fund_date'),
            models.Index(fields=['daily_growth_rate'], name='idx_scrapy_daily_growth'),
            models.Index(fields=['yearly_growth_rate'], name='idx_scrapy_yearly_growth'),
            models.Index(fields=['ranking_position'], name='idx_scrapy_ranking'),
            models.Index(fields=['scrape_date'], name='idx_scrapy_scrape_date'),
        ]
        ordering = ['-nav_date', 'ranking_position']
    
    def __str__(self):
        return f"{self.fund_code} - {self.fund_name} (排名: {self.ranking_position})"


class FinalFundScraper(models.Model):
    """基金排行数据表 - 对应final_fund_scraper表"""
    fund_code = models.CharField(max_length=10, verbose_name='基金代码')
    fund_name = models.CharField(max_length=200, blank=True, verbose_name='基金名称')
    fund_short_name = models.CharField(max_length=100, blank=True, verbose_name='基金简称')
    nav_date = models.DateField(verbose_name='净值日期')
    unit_nav = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True, verbose_name='单位净值')
    cumulative_nav = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True, verbose_name='累计净值')
    daily_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='日收益率(%)')
    weekly_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1周(%)')
    monthly_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1月(%)')
    quarterly_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3月(%)')
    half_year_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近6月(%)')
    yearly_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近1年(%)')
    two_year_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近2年(%)')
    three_year_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='近3年(%)')
    since_inception_return = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='成立来(%)')
    inception_date = models.DateField(null=True, blank=True, verbose_name='成立日期')
    management_fee = models.CharField(max_length=20, blank=True, verbose_name='手续费')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', db_column='create_date')
    update_date = models.DateTimeField(auto_now=True, verbose_name='更新日期')
    
    class Meta:
        db_table = 'final_fund_scraper'
        verbose_name = '基金排行数据'
        verbose_name_plural = '基金排行数据'
        unique_together = [['fund_code', 'nav_date']]
        indexes = [
            models.Index(fields=['fund_code'], name='idx_final_fund_code'),
            models.Index(fields=['nav_date'], name='idx_final_nav_date'),
            models.Index(fields=['fund_code', 'nav_date'], name='idx_final_fund_date'),
            models.Index(fields=['yearly_return'], name='idx_final_yearly_return'),
            models.Index(fields=['fund_name'], name='idx_final_fund_name'),
            models.Index(fields=['update_date'], name='idx_final_update_date'),
        ]
        ordering = ['-nav_date', 'fund_code']
    
    def __str__(self):
        return f"{self.fund_code} - {self.fund_name} ({self.nav_date})"

class FundNavDetail(models.Model):
    """基金历史净值明细表 - 存储基金的历史净值明细数据"""
    fund_code = models.CharField(max_length=10, verbose_name='基金代码')
    nav_date = models.DateField(verbose_name='净值日期')
    unit_nav = models.DecimalField(max_digits=10, decimal_places=4, verbose_name='单位净值')
    accumulated_nav = models.DecimalField(max_digits=10, decimal_places=4, verbose_name='累计净值')
    daily_growth_rate = models.DecimalField(max_digits=8, decimal_places=4, null=True, blank=True, verbose_name='日增长率(%)')
    purchase_status = models.CharField(max_length=20, blank=True, verbose_name='申购状态')
    redemption_status = models.CharField(max_length=20, blank=True, verbose_name='赎回状态')
    dividend_per_unit = models.CharField(max_length=100, blank=True, verbose_name='分红送配信息')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    def __str__(self):
        return f"{self.fund_code}-{self.nav_date}"
    
    class Meta:
        db_table = 'fund_nav_detail_new'
        verbose_name = '基金历史净值明细'
        verbose_name_plural = '基金历史净值明细'
        unique_together = [['fund_code', 'nav_date']]
        ordering = ['-nav_date', 'fund_code']
